//
// Created by ZengYun on 2024/7/9.
//

#include "Fan.h"
#include "Tools.h"

using namespace app::Clusters::FanControl::Attributes;
using namespace app::Clusters::FanControl;
using namespace tools;

namespace {
constexpr
DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(fanAttributes)
    DECLARE_DYNAMIC_ATTRIBUTE(FanMode::Id, INT8U, 1, ATTRIBUTE_MASK_WRITABLE),
    DECLARE_DYNAMIC_ATTRIBUTE(FanModeSequence::Id, INT8U, 1, ATTRIBUTE_MASK_WRITABLE),
    DECLARE_DYNAMIC_ATTRIBUTE(PercentSetting::Id, PERCENT, 1, ATTRIBUTE_MASK_WRITABLE),
    DECLARE_DYNAMIC_ATTRIBUTE(PercentCurrent::Id, PERCENT, 1, 0),
DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();

constexpr CommandId fanIncomingCommands[] = {
        Commands::Step::Id,
        kInvalidCommandId,
};

constexpr EmberAfCluster fanCluster = DECLARE_DYNAMIC_CLUSTER(
        Id,
        fanAttributes,
        ZAP_CLUSTER_MASK(SERVER),
        fanIncomingCommands,
        nullptr);
}

Fan::Fan(const BasicInformation *node) : BridgedDevice(node) {
    ChipLogProgress(DeviceLayer, "Fan");
    mClusters.push_back(fanCluster);
    mPercent = 50;
    mMode = static_cast<uint8_t>(FanModeEnum::kAuto);
}

Protocols::InteractionModel::Status
Fan::ReadAttribute(ClusterId clusterId, AttributeId attributeId, uint8_t *buffer, uint16_t maxReadLength) {
    ChipLogProgress(DeviceLayer, "OnOffAttributes: attrId=%d, maxReadLength=%d", attributeId, maxReadLength);
    if (clusterId != Id) {
        return BridgedDevice::ReadAttribute(clusterId, attributeId, buffer, maxReadLength);
    }
    switch (attributeId) {
        case FanMode::Id:
            GetAttr(buffer, maxReadLength, mMode);
            break;

        case PercentSetting::Id:
        case PercentCurrent::Id:
        {
            GetAttr(buffer, maxReadLength, mPercent);
            break;
        }

        case FeatureMap::Id: {
            uint32_t bitmap = 0x00000000;
            bitmap |= static_cast<uint32_t>(Feature::kMultiSpeed);
            bitmap |= static_cast<uint32_t>(Feature::kAuto);
            bitmap |= static_cast<uint32_t>(Feature::kRocking);
            bitmap |= static_cast<uint32_t>(Feature::kWind);
            bitmap |= static_cast<uint32_t>(Feature::kStep);
            bitmap |= static_cast<uint32_t>(Feature::kAirflowDirection);
            ChipLogProgress(DeviceLayer, "ReadAttribute FeatureMap: %08x", bitmap);
            GetAttr(buffer, maxReadLength, bitmap);
            break;
        }

        default:
            memset(buffer, 0x00, maxReadLength);
            break;
    }
    return Protocols::InteractionModel::Status::Success;
}

Protocols::InteractionModel::Status
Fan::WriteAttribute(ClusterId clusterId, const EmberAfAttributeMetadata *attributeMetadata, uint8_t *buffer) {
    if (clusterId != Id) {
        return BridgedDevice::WriteAttribute(clusterId, attributeMetadata, buffer);
    }

    ChipLogProgress(DeviceLayer, "AttributeWrite attribute:%x", attributeMetadata->attributeId);
    if (attributeMetadata->attributeId == PercentSetting::Id) {
        mPercent = *buffer;
        ChipLogProgress(DeviceLayer, "FanSpeed:%d", mPercent);
        NotifyStatusChanged(Id, PercentSetting::Id);
        NotifyStatusChanged(Id, PercentCurrent::Id);
        auto block = DataBlock(Path(Id, PercentSetting::Id), mPercent);
        SendMessage(&block);
    }

    else if (attributeMetadata->attributeId == FanMode::Id) {
        mMode = *buffer;
        ChipLogProgress(DeviceLayer, "FanMode: %d", mMode);
        NotifyStatusChanged(Id, FanMode::Id);
        auto block = DataBlock(Path(Id, FanMode::Id), mMode);
        SendMessage(&block);
    }
    return chip::Protocols::InteractionModel::Status::Success;
}

ChipError Fan::OnReport(const DataBlock *block) {
    if (block->path.clusterId != Id) {
        return BridgedDevice::OnReport(block);
    }

    if (block->path.attributeId == FanMode::Id) {
        mMode = static_cast<uint8_t>(block->data.asInt());
        ChipLogProgress(DeviceLayer, "FanMode:%d", this->mMode);
        NotifyStatusChanged(Id, FanMode::Id);
    } else if (block->path.attributeId == PercentSetting::Id) {
        mPercent = static_cast<uint8_t>(block->data.asInt());
        ChipLogProgress(DeviceLayer, "FanPercent:%d", mPercent);
        NotifyStatusChanged(Id, PercentSetting::Id);
    } else if (block->path.attributeId == PercentCurrent::Id) {
        mPercent = static_cast<uint8_t>(block->data.asInt());
        ChipLogProgress(DeviceLayer, "FanPercent:%d", mPercent);
        NotifyStatusChanged(Id, PercentCurrent::Id);
    }
    return CHIP_NO_ERROR;
}

